home *** CD-ROM | disk | FTP | other *** search
- package PVS.Hyperbolic;
- //
- // Copyright (C) 1996 by Vladimir Bulatov <V.Bulatov@ic.ac.uk>.
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- // 1. Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // 2. Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- //
- // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- // SUCH DAMAGE.
-
- import PVS.Utils.MathExt;
-
- public class Hyperbolic {
-
- static final double EPS = 1.e-4;
-
- // switch to draw lines instead of arcs
- public static boolean fastLines = false;
-
- /**
- doTranslate() does hyperbolic translation of z
- This translation moves center of hyperbolic plane into point p.
- */
- static Complex c1 = new Complex(),c2 = new Complex(),c3 = new Complex();
-
- public static void doTranslate(Complex z,Complex p){ // z = (z+p)/(1+(p*)*z)
- c1.add(z,p);
- c2.conj(p);
- c3.mul(c2,z);
- c3.add(1);
- z.div(c1,c3);
- }
-
- /**
- doTransform() does most common hyperbolic motion:
- rotation on t.teta over center and translation over t.p;
- */
- public static void doTransform(Complex z,HTransform t){
- // z = (z*teta+p)/(1+(p*)*z)
- c1.mul(z,t.teta);
- c1.add(t.p);
- c2.conj(t.p);
- c3.mul(c2,z);
- c3.add(1);
- z.div(c1,c3);
- }
-
- /**
- does composition of two transformations: t1 and t2
- and puts result in t1
- */
- public static void doTransform(HTransform t1,HTransform t2){
- //teta = (teta1*t2+teta1*p1^*p2)/(1+teta2*p1*p2^);
- //peta = (teta2*p1+p2)/(1+teta2*p1*p2^);
-
- // denominator
- c1.set(t2.p).conj().mul(t1.p).mul(t2.teta).add(1.);
-
- c2.mul(t2.teta,t1.p).add(t2.p);
- c3.set(t1.p).conj().mul(t2.p).add(t2.teta).mul(t1.teta);
-
- t1.p.div(c2,c1);
- t2.teta.div(c3,c1);
- t2.teta.div(t2.teta.abs());
- }
-
- static boolean ParallelArc(Complex z1, Complex z2){
- double ab1 = z1.abs2(),ab2 = z2.abs2();
- double ar1 = z1.arg(),ar2 = z2.arg();
- return ((ab1 < EPS || ab2 < EPS) ||
- ((ab1 >= EPS && ab2 >= EPS) &&
- ((Math.abs(ar1-ar2) < EPS || (Math.abs(ar1-ar2-Math.PI) < EPS) ||
- (Math.abs(ar1-ar2+Math.PI) < EPS)))));
- }
-
- /**
- Euclidean distance between two points
- */
- public static double EuclDistance(Complex z1, Complex z2){
- return Math.sqrt(MathExt.sqr(z1.re-z2.re)+MathExt.sqr(z1.im-z2.im));
- }
-
- /**
- Hyperbolic distance between two points
- */
- public static double HyperDistance(Complex z1, Complex z2){
- // 2*atanh((z1-z2)/(1-z1*z2^));
- c2.set(z2); c2.conj();c2.mul(z1);c2.neg();c2.add(1.);
- c1.sub(z1,z2); c1.div(c3);
- return 2.*MathExt.atanh(c1.abs());
- }
-
- /**
- Hyperbolic distance of euqclidean point from origin
- */
- public static double HyperDistance(Complex z){
- // 2*atanh(z);
- return e2h(z.abs());
- }
-
- /**
- Hyperbolic distance of euqclidean point from origin
- */
- public static double e2h(double x){
- // 2*atanh(x);
- return 2.*MathExt.atanh(x);
- }
-
- /**
- Euclidean distance of hyperbolic point from origin
- */
- public static double h2e(double h){
- return MathExt.tanh(h*0.5);
- }
-
- /**
- Reflects point in givent arc.
- */
- public static void reflect(Complex p,Arc arc){
- if(arc.r == 0.0){ // strait line
- double qx = arc.x, qy = arc.y, px = arc.start, py = arc.angle;
- double denom = MathExt.sqr(qx-px)+ MathExt.sqr(qy-py);
- double t = py*(qx-p.re)-qy*(px-p.re)+p.im*(px-qx);
- p.set(p.re+2*(py-qy)*t, p.im+21*(px+qx)*t);
- } else {
- double denom = MathExt.sqr(p.re-arc.x) + MathExt.sqr(p.im-arc.y);
- double r2 = arc.r*arc.r;
- p.set(arc.x + r2*(p.re-arc.x)/denom, arc.y + r2*(p.im-arc.y)/denom);
- }
- }
-
- /**
- Produces segment of hyperbolic cyrcle, which connects z1 and z2.
- */
- static Complex ccenter = new Complex(),t2 = new Complex(),t1 = new Complex();
- public static Arc getArc(Complex z1, Complex z2, Arc segment){
- if(segment == null)
- segment = new Arc();
-
- if(ParallelArc(z1,z2)){
- segment.r = 0.0;
- segment.x = z1.re;
- segment.y = z1.im;
- segment.start = z2.re;
- segment.angle = z2.im;
- return segment;
- }
- double s1 = 1 + z1.abs2(), s2 = 1 + z2.abs2();
- double norm = 1/(2*(z1.re*z2.im - z2.re*z1.im));
- ccenter.set((s1*z2.im-s2*z1.im)*norm,
- -(s1*z2.re-s2*z1.re)*norm);
- double cradius = EuclDistance(ccenter,z2);
-
- double angle1, angle2, minang, angle;
-
- t1.set(z1); t1.sub(ccenter); angle1= t1.arg(); //Arg(z1-ccenter);
- t2.set(z2); t2.sub(ccenter); angle2= t2.arg(); //Arg(z2-ccenter);
-
- if(angle1 < 0.0) angle1 += 2.0*Math.PI;
- if(angle2 < 0.0) angle2 += 2.0*Math.PI;
- minang = angle1;//(angle1 < angle2) ? angle1 : angle2;
- angle = angle2 - angle1;//(angle1 > angle2) ? angle1-angle2 : angle2-angle1;
- if(angle > Math.PI)
- angle -= 2.0*Math.PI;
- else if(angle < -Math.PI){
- angle += 2.0*Math.PI;
- }
- segment.x = ccenter.re;
- segment.y = ccenter.im;
- segment.r = cradius;
- segment.start = minang;
- segment.angle = angle;
- return segment;
-
- }
-
- /**
- Draw a geodesic arc which goes from a given point z1 to a given point z2
- */
- static Arc arc = new Arc();
- public static void drawGeodArc(Graphics2d g, Complex z1, Complex z2){
- if(fastLines)
- g.drawLine(z1.re, z1.im, z2.re, z2.im);
- else {
- getArc(z1,z2,arc);
- g.drawArc(arc);
- }
- }
-
- public static void drawPoly(Graphics2d g, Complex[] vert, int nvert){
- Complex c = vert[nvert-1];
- for(int i=0; i < nvert; i++){
- drawGeodArc(g,c,vert[i]);
- c = vert[i];
- }
- }
-
- public static void fillPoly(Graphics2d g, Complex[] vert, int nvert){
- Complex c = vert[nvert-1];
- Arc[] arc = new Arc[nvert];
- for(int i=0; i < nvert; i++){
- arc[i] = getArc(c,vert[i],null);
- c = vert[i];
- }
- g.fillArcs(arc);
- }
-
- }
-